package com.zd.ticketing.common.utils;

import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import com.github.wxpay.sdk.WXPayUtil;
import com.zd.common.common.utils.LogUtils;

public class WXPayUtils extends WXPayUtil{
	
	/**
	 * 重写XML信息验证
	 * @param strXML
	 * @return
	 * @throws Exception
	 */
	 public static Map<String, String> xmlToMap(String strXML) throws Exception {
	        Map<String, String> data = new HashMap<String, String>();
	        DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
	        
	        String FEATURE = null;
	        try {
	        	// This is the PRIMARY defense. If DTDs (doctypes) are disallowed, almost all XML entity attacks are prevented
	        	// Xerces 2 only - http://xerces.apache.org/xerces2-j/features.html#disallow-doctype-decl
	        	FEATURE = "http://apache.org/xml/features/disallow-doctype-decl";
	        	documentBuilderFactory.setFeature(FEATURE, true);
	        	
	        	// If you can't completely disable DTDs, then at least do the following:
	        	// Xerces 1 - http://xerces.apache.org/xerces-j/features.html#external-general-entities
	        	// Xerces 2 - http://xerces.apache.org/xerces2-j/features.html#external-general-entities
	        	// JDK7+ - http://xml.org/sax/features/external-general-entities 
	        	FEATURE = "http://xml.org/sax/features/external-general-entities";
	        	documentBuilderFactory.setFeature(FEATURE, false);
	        	
	        	// Xerces 1 - http://xerces.apache.org/xerces-j/features.html#external-parameter-entities
	        	// Xerces 2 - http://xerces.apache.org/xerces2-j/features.html#external-parameter-entities
	        	// JDK7+ - http://xml.org/sax/features/external-parameter-entities 
	        	FEATURE = "http://xml.org/sax/features/external-parameter-entities";
	        	documentBuilderFactory.setFeature(FEATURE, false);
	        	
	        	// Disable external DTDs as well
	        	FEATURE = "http://apache.org/xml/features/nonvalidating/load-external-dtd";
	        	documentBuilderFactory.setFeature(FEATURE, false);
	        	
	        	// and these as well, per Timothy Morgan's 2014 paper: "XML Schema, DTD, and Entity Attacks"
	        	documentBuilderFactory.setXIncludeAware(false);
	        	documentBuilderFactory.setExpandEntityReferences(false);
	        	
	        	// And, per Timothy Morgan: "If for some reason support for inline DOCTYPEs are a requirement, then 
	        	// ensure the entity settings are disabled (as shown above) and beware that SSRF attacks
	        	// (http://cwe.mitre.org/data/definitions/918.html) and denial 
	        	// of service attacks (such as billion laughs or decompression bombs via "jar:") are a risk."
	        	
	        	// remaining parser logic
	        } catch (ParserConfigurationException e) {
	        	// This should catch a failed setFeature feature
	        	LogUtils.info("ParserConfigurationException was thrown. The feature '" +
	        	FEATURE + "' is probably not supported by your XML processor.");
	        }
	        
	        DocumentBuilder documentBuilder= documentBuilderFactory.newDocumentBuilder();
	        InputStream stream = new ByteArrayInputStream(strXML.getBytes("UTF-8"));
	        org.w3c.dom.Document doc = documentBuilder.parse(stream);
	        doc.getDocumentElement().normalize();
	        NodeList nodeList = doc.getDocumentElement().getChildNodes();
	        for (int idx=0; idx<nodeList.getLength(); ++idx) {
	            Node node = nodeList.item(idx);
	            if (node.getNodeType() == Node.ELEMENT_NODE) {
	                org.w3c.dom.Element element = (org.w3c.dom.Element) node;
	                data.put(element.getNodeName(), element.getTextContent());
	            }
	        }
	        try {
	            stream.close();
	        }
	        catch (Exception ex) {

	        }
	        return data;
	    }
}
